001 package net.sf.xdc.util;
002
003 /*
004 * Copyright 2005-2006 Jens Voß.
005 *
006 * Licensed under the GNU Lesser General Public License (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 * http://opensource.org/licenses/lgpl-license.php
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019 import java.io.FileNotFoundException;
020 import java.io.IOException;
021 import java.io.InputStream;
022 import java.io.Reader;
023 import java.io.StringWriter;
024 import java.net.MalformedURLException;
025 import java.net.URL;
026 import java.nio.charset.Charset;
027 import java.util.Enumeration;
028 import java.util.HashMap;
029 import java.util.Iterator;
030 import java.util.Map;
031 import java.util.Properties;
032 import javax.xml.transform.Result;
033 import javax.xml.transform.Source;
034 import javax.xml.transform.Transformer;
035 import javax.xml.transform.TransformerException;
036 import javax.xml.transform.TransformerFactory;
037 import javax.xml.transform.dom.DOMResult;
038 import javax.xml.transform.dom.DOMSource;
039 import javax.xml.transform.stream.StreamResult;
040 import javax.xml.transform.stream.StreamSource;
041
042 import org.apache.log4j.Logger;
043 import org.apache.xalan.processor.TransformerFactoryImpl;
044 import org.apache.xalan.transformer.TransformerImpl;
045 import org.w3c.dom.Document;
046 import org.w3c.dom.Element;
047 import org.xml.sax.ContentHandler;
048 import org.xml.sax.helpers.LocatorImpl;
049
050 /**
051 * This is a utility class containg various method related to XSLT
052 * transformations.
053 *
054 * @author Jens Voß
055 * @since 0.5
056 * @version 0.5
057 */
058 public class XslUtils {
059
060 private static final Logger LOG = Logging.getLogger();
061 private static final TransformerFactory FACTORY =
062 TransformerFactory.newInstance();
063
064 private static final Map XSL_CACHE = new HashMap();
065
066 static {
067 if (FACTORY instanceof TransformerFactoryImpl) {
068 FACTORY.setAttribute(TransformerFactoryImpl.FEATURE_SOURCE_LOCATION,
069 Boolean.TRUE);
070 }
071 }
072
073 private static Element createConfiguration(Map tables) throws XmlException {
074 Document doc = XmlUtils.createDocument();
075 Element configEl = doc.createElement("configuration");
076 for (Iterator tableNames = tables.keySet().iterator(); tableNames.hasNext();) {
077 String tableName = (String) tableNames.next();
078 Properties table = (Properties) tables.get(tableName);
079 Element tableEl = doc.createElement("table");
080 tableEl.setAttribute("name", tableName);
081 for (Enumeration keys = table.propertyNames(); keys.hasMoreElements();) {
082 String key = (String) keys.nextElement();
083 Element entryEl = doc.createElement("entry");
084 tableEl.appendChild(entryEl);
085 Element keyEl = doc.createElement("key");
086 keyEl.appendChild(doc.createTextNode(key));
087 entryEl.appendChild(keyEl);
088 Element valEl = doc.createElement("value");
089 valEl.appendChild(doc.createTextNode(table.getProperty(key)));
090 entryEl.appendChild(valEl);
091 }
092 configEl.appendChild(tableEl);
093 }
094 return configEl;
095 }
096
097 private static void transform(Source xml, Source xsl, Map tables,
098 Result out)
099 throws TransformerException, XmlException {
100 Transformer transformer = FACTORY.newTransformer(xsl);
101 TransformerImpl impl = ((TransformerImpl) transformer);
102 ContentHandler handler = impl.getInputContentHandler();
103 handler.setDocumentLocator(new LocatorImpl());
104 XSL_CACHE.put(xsl.getSystemId(), transformer);
105 transformer.clearParameters();
106 if (tables != null) {
107 transformer.setParameter("configuration", createConfiguration(tables));
108 }
109 transformer.transform(xml, out);
110 }
111
112 private static void transform(Source xml, Transformer transformer,
113 Map tables, Result out)
114 throws TransformerException, XmlException {
115 transformer.clearParameters();
116 if (tables != null) {
117 transformer.setParameter("configuration", createConfiguration(tables));
118 }
119 transformer.transform(xml, out);
120 }
121
122 private static Document transform(Source xml, Source xsl, Map tables)
123 throws TransformerException, XmlException {
124 Document retVal = XmlUtils.createDocument();
125 transform(xml, xsl, tables, new DOMResult(retVal));
126 return retVal;
127 }
128
129 private static Document transform(Source xml, Transformer transformer, Map tables)
130 throws TransformerException, XmlException {
131 Document retVal = XmlUtils.createDocument();
132 transform(xml, transformer, tables, new DOMResult(retVal));
133 return retVal;
134 }
135
136 /**
137 * This method attempts to transform an XML structure contained in a file
138 * using an XSLT stylesheet contained in a resource (which can be loaded
139 * by the <code>Classloader</code> of this class) into a DOM
140 * <code>Document</code>.
141 *
142 * @param xmlFileName The path (in the file system) of the XML input file
143 * @param charset The file encoding charset
144 * @param xslResourceName The name of the XSLT stylesheet resource; either
145 * the name by which the resource is accessed by the
146 * <code>Classloader</code> or any valid URL
147 * @param tables Optional key-value pairs passed as stylesheet parameters
148 * to the transformer
149 * @return An XML document which is the result of the transformation
150 * @throws XmlException
151 */
152 public static Document transform(String xmlFileName, Charset charset,
153 String xslResourceName, Map tables)
154 throws XmlException {
155 Reader in = null;
156 try {
157 in = IOUtils.getReader(xmlFileName, charset);
158 StreamSource source = new StreamSource(xmlFileName);
159 source.setSystemId(xmlFileName);
160 return transform(source, xslResourceName, tables);
161 }
162 catch (FileNotFoundException e) {
163 throw new XmlException(e);
164 }
165 finally {
166 try {
167 if (in != null) {
168 in.close();
169 }
170 }
171 catch (IOException e) {
172 e.printStackTrace();
173 }
174 }
175 }
176
177 /**
178 * This method attempts to transform an XML structure contained in a DOM
179 * <code>Document</code> using an XSLT stylesheet contained in a resource
180 * (which can be loaded by the <code>Classloader</code> of this class)
181 * into a DOM <code>Document</code>.
182 *
183 * @param xml The DOM document used as XML input
184 * @param xslResourceName The name of the XSLT stylesheet resource; either
185 * the name by which the resource is accessed by the
186 * <code>Classloader</code> or any valid URL
187 * @param tables Optional key-value pairs passed as stylesheet parameters
188 * to the transformer
189 * @return An XML document which is the result of the transformation
190 * @throws XmlException
191 */
192 public static Document transform(Document xml, String xslResourceName,
193 Map tables)
194 throws XmlException {
195 return transform(new DOMSource(xml), xslResourceName, tables);
196 }
197
198 private static Document transform(Source xml, String xslResourceName,
199 Map tables) throws XmlException {
200 InputStream xsl = null;
201 try {
202 URL xslResource;
203 try {
204 xslResource = new URL(xslResourceName);
205 }
206 catch (MalformedURLException e) {
207 xslResource = new URL("classpath:/" + xslResourceName);
208 }
209 Transformer transformer = (Transformer) XSL_CACHE.get(xslResource.toExternalForm());
210 if (transformer != null) {
211 if (LOG.isDebugEnabled()) {
212 LOG.debug("Using cached transformer for xsl resource "
213 + xslResourceName);
214 }
215 return transform(xml, transformer, tables);
216 }
217 else {
218 if (LOG.isDebugEnabled()) {
219 LOG.debug(
220 "Using new transformer for xsl resource " + xslResourceName);
221 }
222 xsl = xslResource.openStream();
223 StreamSource source = new StreamSource(xsl);
224 source.setSystemId(xslResource.toExternalForm());
225 return transform(xml, source, tables);
226 }
227 }
228 catch (MalformedURLException e) {
229 throw new XmlException(e);
230 }
231 catch (TransformerException e) {
232 throw new XmlException(e);
233 }
234 catch (IOException e) {
235 throw new XmlException(e);
236 }
237 finally {
238 if (xsl != null) {
239 try {
240 xsl.close();
241 }
242 catch (IOException e) {
243 throw new XmlException(e);
244 }
245 }
246 }
247 }
248
249 /**
250 * This method attempts to transform an XML structure contained in a file
251 * using an XSLT stylesheet contained in a resource (which can be loaded
252 * by the <code>Classloader</code> of this class) into a <code>String</code>.
253 *
254 * @param xmlFileName The path (in the file system) of the XML input file
255 * @param xslResourceName The name of the XSLT stylesheet resource; either
256 * the name by which the resource is accessed by the
257 * <code>Classloader</code> or any valid URL
258 * @param tables Optional key-value pairs passed as stylesheet parameters
259 * to the transformer
260 * @return A String containing the XML document which is the result of the
261 * transformation
262 * @throws XmlException
263 */
264 public static String transformToString(String xmlFileName, String xslResourceName, Map tables)
265 throws XmlException {
266 InputStream xsl = null;
267 try {
268 URL xslResource = new URL("classpath:/" + xslResourceName);
269 xsl = xslResource.openStream();
270 StreamSource source = new StreamSource(xsl);
271 source.setSystemId(xslResource.toExternalForm());
272
273 StringWriter retVal = new StringWriter();
274 StreamResult result = new StreamResult(retVal);
275 transform(new StreamSource(xmlFileName), source, tables, result);
276 retVal.close();
277 return retVal.getBuffer().toString();
278 }
279 catch (MalformedURLException e) {
280 throw new XmlException(e);
281 }
282 catch (TransformerException e) {
283 throw new XmlException(e);
284 }
285 catch (IOException e) {
286 throw new XmlException(e);
287 }
288 finally {
289 if (xsl != null) {
290 try {
291 xsl.close();
292 }
293 catch (IOException e) {
294 throw new XmlException(e);
295 }
296 }
297 }
298 }
299
300 private XslUtils() {
301 }
302
303 }